package com.fundynamic.codekata;

public class BowlingGame implements Game {

	private Frame frames[] = new Frame[10];
	private int currentFrame = 0;
	
	public BowlingGame() {
		for (int i = 0; i < frames.length; i++) {
			if (i < 9) {
				frames[i] = new Frame();
			} else {
				frames[i] = new TenthFrame();
			}
		}
	}
	
	public void roll(int pins) throws CheatingException {
		Frame frame = getCurrentOrNextFrame();
		frame.roll(pins);
	}

	protected Frame getCurrentOrNextFrame() {
		Frame frame = frames[currentFrame];
		if (frame.isFinished()) {
			currentFrame++;
			return frames[currentFrame];
		}
		return frame;
	}

	public int score() {
		int score = 0;
		for (int i = 0; i < frames.length; i++) {
			int frameScore = calculateScoreForFrame(i);
			score += frameScore;
		}
		
		return score;
	}
	
	private int calculateScoreForFrame(int i) {
		Frame frame = getFrame(i);
		
		// tenth frame is all pins nocked down (in 2 or 3 rolls)
		if (frame instanceof TenthFrame) {
			return frame.totalPinsNockedDown();
		}
		
		int nextFrameId = i + 1;
		
		if (frame.isStrike()) {
			Frame nextFrame = getFrame(nextFrameId);
			int firstRoll, secondRoll;
			if (nextFrame.isStrike()) {
				firstRoll = 10;
				Frame nextNextFrame = getFrame((nextFrameId + 1));
				secondRoll = nextNextFrame.getPinsRolledDownForAttempt(1);
			} else {
				firstRoll = nextFrame.getPinsRolledDownForAttempt(1);
				secondRoll = nextFrame.getPinsRolledDownForAttempt(2);
			}
			
			return 10 + firstRoll + secondRoll;	
		}
		
		if (frame.isSpare()) {
			Frame nextFrame = getFrame(nextFrameId);
			return 10 + nextFrame.getPinsRolledDownForAttempt(1); 
		}
		
		return frame.totalPinsNockedDown();
	}

	public Frame getFrame(int i) {
		return frames[i];
	}

}
